#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/signal.h>
#include <sys/wait.h>

#include "../../common/include/filesystem.h"

#include "../include/general.h"
#include "../include/commonTCP.h"
#include "../include/common.h"

void sndTCPAns(int newsockfd, int code)
{
    int nwrite, anslen;
    char answ[3] = {0};

    sprintf (answ, "%d", code);
    anslen = strlen ((char *)answ);

    if ((nwrite = write(newsockfd, answ, anslen)) == -1)
        fatal("message write failed\n");

    return;
}

int rcvTCPAns(int newsockfd)
{

    int ans;
    char msgbuf[3] = {0};


    if (read (newsockfd, msgbuf, 2) < 0)
        fatal ("msg read failed\n");

    sscanf(msgbuf, "%d", &ans);

    return ans;
}


int
send_data_TCP (int fd, char * s_msg, int size)
{
    int n_size;

    if (size < 0 || s_msg == NULL)
        return -1;

    n_size = write(fd, s_msg, size);

    if (n_size < 0)
        return -2;

    return 1;
}

int readsizeTCP(int fd)
{
    char chsize[17];
    int i = 0;
    int size;

    if (readWithTimeout(fd, chsize, 1, TIMEOUT) < 0)
        fatal ("msg read failed\n");

    if (readWithTimeout(fd, chsize, 1, TIMEOUT) < 0)
        fatal ("msg read failed\n");

    while (chsize[i] != ',')
    {
        if (readWithTimeout(fd, &(chsize[++i]), 1, TIMEOUT) < 0)
            fatal ("msg read failed\n");
    }

    chsize[i] = 0;
    sscanf (chsize, "%d", &size);

    return size;
}

int readcomTCP(int fd)
{
    char chsize[17];
    int i = 0;
    int size;


//     func con problemas
    while (i < 2)
    {
        if (readWithTimeout(fd, &(chsize[i++]), 1, TIMEOUT) < 0)
        {
            fatal ("msg read failed\n");
            return -1;
        }
    }

    chsize[i] = 0;
    sscanf (chsize, "%d", &size);

    return size;
}

int snd_file_TCP (int newsockfd, char * fname, int isdir)
{
    unsigned int fsize;
    FILE * pfile;
    char buf[BUF_SIZE] = {0};
    int acum, nread, back, name_len, tot_len;
    char answ[MSGSIZE] = {0};
    char msg[MSGSIZE] = {0};
    int cant = 0;

    if (isDir(fname) == 1)
    {
        sprintf(msg, "%d,%s", -1, fname);
        name_len = strlen(msg);
        sprintf(answ, "%d,%d,%d,%s", SND_FILE, name_len, -1, fname);

        tot_len = strlen (answ);

        if ((send_data_TCP(newsockfd, answ, tot_len)) < 0)
        {
            fatal ("send dir failed\n");
            return -1;
        }

        if ((back = rcvTCPAns(newsockfd)) != COM_ACK)
        {
            fatal ("Error received\n");
            return -1;
        }

        return 1;
    }

    fsize = getFileSize(fname);


    if ((pfile = fopen(fname, "r")) == NULL)
        fatal ("file open failed\n");

    sprintf(msg, "%d,%s", fsize, fname);
    name_len = strlen(msg);
    sprintf(answ, "%d,%d,%s", SND_FILE, name_len, msg);

    tot_len = strlen (answ);

    if ((send_data_TCP (newsockfd, answ, tot_len)) < 0)
    {
        fatal ("send file failed\n");
        return -1;
    }

    if ((back = rcvTCPAns(newsockfd)) != COM_ACK)
    {
        fatal ("Error received\n");
    }

    acum = 0;
    while (acum < fsize)
    {
        if ((fsize - acum) > BUF_SIZE)
            cant = BUF_SIZE;
        else
            cant = (fsize - acum);

        nread = fread(buf, 1, cant, pfile);
        if (nread < BUF_SIZE && nread < (fsize - acum))
        {
                fatal ("File read failure\n");
        }

        acum += nread;

        do
        {
            if ((send_data_TCP (newsockfd, buf, nread)) < 0)
            {
                fatal ("send dir failed\n");
                return -1;
            }

            back = rcvTCPAns(newsockfd);

        }while (back != COM_ACK);
    }


    return 1;

}

int
walkDirTCP(char *path, char *relPath, int newsockfd)
{
    DIR *dip;
    struct dirent *dit;
    int i = 0;
    char *ext;
    char currPath[FILE_LEN];
    char currRelPath[FILE_LEN];

    /*
    * Open a directory stream to argv[1] and make sure
        * it's a readable and valid (directory) */
    if ((dip = opendir(path)) == NULL)
    {
        perror("opendir");
        return 0;
    }

    /*
    * Read in the files from argv[1] and print */
    while ((dit = readdir(dip)) != NULL)
    {
        i++;
        sprintf(currPath, "%s/%s", path, dit->d_name);

        /*TODO: Si se le pasa un path roto es probable que muera,
        no se pone ahora porque toda la info sale de readdir
        No envia archivos ni dirs que empiecen con '.'*/
        if (isDir(currPath))
        {
            if ( 0 == strcmp(".", dit->d_name) ||
                 0 == strcmp("..", dit->d_name) )
                continue;

            sprintf(currRelPath, "%s/%s", relPath, dit->d_name);


            if (snd_file_TCP (newsockfd, currPath, 1) < 0)
            {
                fatal ("Error sending file\n");
            }

            walkDirTCP(currPath, currRelPath, newsockfd);
        }
        else
        {
            /* Don't send .mine's */
            ext = fileExt(dit->d_name);
            if (    0 == strcmp(".mine", ext) ||
                    0 == strcmp(".new", ext) )
                continue;

            if (snd_file_TCP (newsockfd, currPath, 0) < 0)
            {
                fatal ("Error sending file\n");
            }
        }
    }

    /*
    * Close the stream. And check for errors. */
    if (closedir(dip) == -1)
    {
        perror("closedir");
        return 0;
    }

    return 1;
}

